using System;
using Firestarter.Test.Base;
using FireStarterModeller.BO;
using Habanero.Base;
using Habanero.Base.Exceptions;
using Habanero.BO;
using NUnit.Framework;
using Rhino.Mocks;

namespace FireStarterModeller.Test.BO
{
    [TestFixture]
    public class TestPropertyCompulsoryRule
    {
        [SetUp]
        public void SetupTest()
        {
            //Runs every time that any testmethod is executed
            TestUtilsDomain.SetupTest();
            BORegistry.DataAccessor = new DataAccessorInMemory();
        }

        [TestFixtureSetUp]
        public void TestFixtureSetup()
        {
            //Code that is executed before any test is run in this class. If multiple tests
            // are executed then it will still only be called once.
            TestUtilsDomain.SetupFixture();
        }

        [Test]
        public void Test_Construct()
        {
            //---------------Set up test pack-------------------
            string propertyName = TestUtilsShared.GetRandomString();
            ErrorLevel errorLevel = ErrorLevel.Warning;
//            IBusinessObject businessObject = CreateBusinessObjectWithClassNameAndSpecifiedProp(propertyName);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            PropertyCompulsoryRule propertyCompulsoryRule = new PropertyCompulsoryRule(propertyName,errorLevel);
            //---------------Test Result -----------------------
            IBusinessObjectRule rule = TestUtilsShared.AssertIsInstanceOf<IBusinessObjectRule>(propertyCompulsoryRule);
            Assert.AreEqual(ErrorLevel.Warning, rule.ErrorLevel);
        }

//        [Test]
//        public void Test_Construct_WhenBoIsNull_ShouldThrowError()
//        {
//            //---------------Set up test pack-------------------
//            string propertyName = TestUtilsShared.GetRandomString();
//            ErrorLevel errorLevel = TestUtilsShared.GetRandomEnum<ErrorLevel>();
//            //---------------Assert Precondition----------------
//            //---------------Execute Test ----------------------
//            try
//            {
//                new PropertyCompulsoryRule(null, propertyName, errorLevel);
//                Assert.Fail("Expected to throw an ArgumentNullException");
//            }
//            //---------------Test Result -----------------------
//            catch (ArgumentNullException ex)
//            {
//                Assert.AreEqual("businessObject", ex.ParamName);
//            }
//        }

        [Test]
        public void Test_Construct_WhenPropertyNameIsNull_ShouldThrowError()
        {
            //---------------Set up test pack-------------------
//            string propertyName = TestUtilsShared.GetRandomString();
            ErrorLevel errorLevel = TestUtilsShared.GetRandomEnum<ErrorLevel>();
//            IBusinessObject businessObject = CreateBusinessObjectWithClassNameAndSpecifiedProp(propertyName);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new PropertyCompulsoryRule(null,errorLevel);
                Assert.Fail("Expected to throw an ArgumentNullException");
            }
            //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("propertyName", ex.ParamName);
            }
        }

        [Test]
        public void Test_Construct_WhenPropertyDoesntExistOnBO_ShouldThrowError()
        {
            //---------------Set up test pack-------------------
            string propertyName = TestUtilsShared.GetRandomString();
            ErrorLevel errorLevel = TestUtilsShared.GetRandomEnum<ErrorLevel>(); 
            IBusinessObject businessObject = CreateBusinessObjectWithClassName();
            businessObject.Stub(t => t.Props).Return(MockRepository.GenerateStub<IBOPropCol>());
            businessObject.Props.Stub(t => t.Contains(propertyName)).Return(false);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                PropertyCompulsoryRule rule = new PropertyCompulsoryRule(propertyName,errorLevel);
                rule.IsValid(businessObject);
                Assert.Fail("Expected to throw an HabaneroDeveloperException");
            }
            //---------------Test Result -----------------------
            catch (HabaneroDeveloperException ex)
            {
                string expected = string.Format("The property '{0}' does not exist on the BO '{1}'.", 
                    propertyName, businessObject.ClassDef.ClassName );
                Assert.AreEqual(expected, ex.DeveloperMessage);
                Assert.AreEqual(expected, ex.Message);
            }
        }

        [Test]
        public void Test_Name_ShouldBuildFromBOAndPropertyName()
        {
            //---------------Set up test pack-------------------
            string propertyName = TestUtilsShared.GetRandomString();
            ErrorLevel errorLevel = TestUtilsShared.GetRandomEnum<ErrorLevel>();
            IBusinessObject businessObject = CreateBusinessObjectWithClassNameAndSpecifiedProp(propertyName);
            PropertyCompulsoryRule propertyCompulsoryRule = new PropertyCompulsoryRule(propertyName,errorLevel);
            //---------------Assert Precondition----------------
            Assert.IsNotNull(businessObject.ClassDef);
            Assert.IsNotNull(businessObject.ClassDef.ClassName);
            //---------------Execute Test ----------------------
            string ruleName = propertyCompulsoryRule.Name;
            //---------------Test Result -----------------------
//            string expected = businessObject.ClassDef.ClassName + propertyName + "IsCompulsory";
            Assert.AreEqual("PropertyCompulsoryRule", ruleName);
        }

        [Test]
        public void Test_Message_ShouldBuildFromBOAndPropertyName()
        {
            //---------------Set up test pack-------------------
            string propertyName = TestUtilsShared.GetRandomString();
            ErrorLevel errorLevel = TestUtilsShared.GetRandomEnum<ErrorLevel>();
            IBusinessObject businessObject = CreateBusinessObjectWithClassNameAndSpecifiedProp(propertyName);
            PropertyCompulsoryRule propertyCompulsoryRule = new PropertyCompulsoryRule(propertyName,errorLevel);
            //---------------Assert Precondition----------------
            Assert.IsNotNull(businessObject.ClassDef);
            Assert.IsNotNull(businessObject.ClassDef.ClassName);
            //---------------Execute Test ----------------------
            propertyCompulsoryRule.IsValid(businessObject);
            string message = propertyCompulsoryRule.Message;
            //---------------Test Result -----------------------
            string expected = string.Format("'{0}.{1}' is a compulsory field and has no value.", businessObject.ClassDef.ClassName, propertyName);
            Assert.AreEqual(expected, message);
        }

        [Test]
        public void Test_IsValid_WhenPropHasValue_ShouldReturnTrue()
        {
            //---------------Set up test pack-------------------
            string propertyName = TestUtilsShared.GetRandomString();
            ErrorLevel errorLevel = TestUtilsShared.GetRandomEnum<ErrorLevel>();
            IBusinessObject businessObject = CreateBusinessObjectWithClassNameAndSpecifiedProp(propertyName);
            businessObject.Props[propertyName].Value = new object();
            PropertyCompulsoryRule propertyCompulsoryRule = new PropertyCompulsoryRule(propertyName,errorLevel);
            //---------------Assert Precondition----------------
            Assert.IsNotNull(businessObject.Props[propertyName].Value);
            //---------------Execute Test ----------------------
            bool isValid = propertyCompulsoryRule.IsValid(businessObject);
            //---------------Test Result -----------------------
            Assert.IsTrue(isValid);
        }

        [Test]
        public void Test_IsValid_WhenPropValueIsNull_ShouldReturnFalse()
        {
            //---------------Set up test pack-------------------
            string propertyName = TestUtilsShared.GetRandomString();
            ErrorLevel errorLevel = TestUtilsShared.GetRandomEnum<ErrorLevel>();
            IBusinessObject businessObject = CreateBusinessObjectWithClassNameAndSpecifiedProp(propertyName);
            businessObject.Props[propertyName].Value = null;
            PropertyCompulsoryRule propertyCompulsoryRule = new PropertyCompulsoryRule(propertyName,errorLevel);
            //---------------Assert Precondition----------------
            Assert.IsNull(businessObject.Props[propertyName].Value);
            //---------------Execute Test ----------------------
            bool isValid = propertyCompulsoryRule.IsValid(businessObject);
            //---------------Test Result -----------------------
            Assert.IsFalse(isValid);
        }

        private static IBusinessObject CreateBusinessObjectWithClassName()
        {
            IBusinessObject businessObject = MockRepository.GenerateStub<IBusinessObject>();
            businessObject.ClassDef = MockRepository.GenerateStub<IClassDef>();
            businessObject.ClassDef.ClassName = TestUtilsShared.GetRandomString();
            return businessObject;
        }

        private static IBusinessObject CreateBusinessObjectWithClassNameAndSpecifiedProp(string propertyName)
        {
            IBusinessObject businessObject = CreateBusinessObjectWithClassName();
            businessObject.Stub(t => t.Props).Return(MockRepository.GenerateStub<IBOPropCol>());
            businessObject.Props.Stub(t => t[propertyName]).Return(MockRepository.GenerateStub<IBOProp>());
            businessObject.Props.Stub(t => t.Contains(propertyName)).Return(true);
            return businessObject;
        }
    }
}